package com.lxy.user.service.impl;

import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lxy.api.client.EquipmentClient;
import com.lxy.common.constant.QueueConstant;
import com.lxy.common.constant.ResponseConstant;
import com.lxy.common.domain.common.R;
import com.lxy.common.domain.dto.MaintenanceScheduleDTO;
import com.lxy.common.domain.dto.MaintenanceUsersDTO;
import com.lxy.common.domain.po.Repair;
import com.lxy.common.domain.vo.MaintenanceSchedulesVO;
import com.lxy.common.domain.vo.RepairUserVO;
import com.lxy.common.enums.MailTitle;
import com.lxy.common.enums.Operation;
import com.lxy.common.utils.UserContext;
import com.lxy.common.utils.ValidateCodeUtils;
import com.lxy.user.config.JwtProperties;
import com.lxy.user.domain.dto.*;
import com.lxy.user.domain.po.Address;
import com.lxy.user.domain.po.DailyMaintenance;
import com.lxy.user.domain.po.LogStatus;
import com.lxy.user.domain.po.User;
import com.lxy.user.domain.vo.ForgetPasswordVO;
import com.lxy.user.domain.vo.FreezeOrUnFreezeUserVO;
import com.lxy.user.domain.vo.UserLoginVO;
import com.lxy.user.domain.vo.UserVO;
import com.lxy.user.enums.Permission;
import com.lxy.user.enums.UserStatus;
import com.lxy.user.mapper.UserMapper;
import com.lxy.user.service.AddressService;
import com.lxy.user.service.DailyMaintenanceService;
import com.lxy.user.service.LogStatusService;
import com.lxy.user.service.UserService;
import com.lxy.user.utils.AliOssUtil;
import com.lxy.user.utils.JwtTool;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;


@Slf4j
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

//    private final PasswordEncoder passwordEncoder;
    private final JwtTool jwtTool;
    private final JwtProperties jwtProperties;
    private final JavaMailSenderImpl javaMailSender;
    private final RedisTemplate redisTemplate;
    private final AddressService addressService;
    private final RabbitTemplate rabbitTemplate;
    private final DailyMaintenanceService dailyMaintenanceService;
    private final LogStatusService logStatusService;
    private final EquipmentClient equipmentClient;
    private final AliOssUtil aliOssUtil;


    @Override
    public R<UserLoginVO> login(LoginFormDTO loginFormDTO) {
        //提取账号密码
        String username=loginFormDTO.getUsername();
        String password= loginFormDTO.getPassword();
        //查询数据库
        LambdaQueryWrapper<User> lambdaQueryWrapper=new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getUsername,username);
        User user = getOne(lambdaQueryWrapper);
        //对用户名、密码进行判断
        Assert.notNull(user,ResponseConstant.USERNAME_OR_PASSWORD_WRONG);
        if(user.getStatus()== UserStatus.FROZEN){
            return R.error("账号被冻结!");
        }
        password = DigestUtils.md5DigestAsHex(password.getBytes());
        if(!password.equals(user.getPassword())) {
            return R.error(ResponseConstant.USERNAME_OR_PASSWORD_WRONG);
        }
        //生成token
        String token = jwtTool.createToken(user.getId(), jwtProperties.getTokenTTL());
//        // 测试使用
//        UserContext.setUser(user.getId());
        //封装VO并返回
        UserLoginVO vo=new UserLoginVO();
        //获取用户权限
        vo.setPermission(user.getPermission());
        vo.setToken(token);
        vo.setUsername(user.getUsername());
        vo.setUserId(user.getId());
        return R.ok(vo);
    }

    public R sendMail(MailTitle title, String text, String email) throws Exception {
        LambdaQueryWrapper<User> lambdaQueryWrapper=new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getEmail,email);
        User user  = getOne(lambdaQueryWrapper);
       if(title.equals(MailTitle.SEND_CODE_REGISTRATION)){
           //判断邮箱是否被注册过(注册用)
           if(user!=null){
               return R.error("邮箱已存在，请更换");
           }
       }else if(title.equals(MailTitle.SEND_CODE_FORGETPASSWORD)){
           if(user==null){
               return R.error("用户不存在，请先注册");
           }
       }
        SimpleMailMessage mailMessage=new SimpleMailMessage();
        System.out.println("当前时间"+new Date());
        mailMessage.setSubject(title.getDesc());
        //发送人
        mailMessage.setFrom("3319725459@qq.com");
        //接收人
        mailMessage.setTo(email);
        //判断邮件类型，如果是发送验证码，则需要对redis进行操作
        if(title.equals(MailTitle.SEND_CODE_REGISTRATION)||title.equals(MailTitle.SEND_CODE_FORGETPASSWORD)){
            //创建key
            String key="";
            if(title.equals(MailTitle.SEND_CODE_REGISTRATION)){
                key=email+ Operation.REGISTRATION;
            }else {
                key=email+ Operation.FORGET_PASSWORD;
            }
            //检查是否存在这条缓存
            ValueOperations valueOperations = redisTemplate.opsForValue();
            if(valueOperations.get(key)!=null){
                //如果存在则删除
                redisTemplate.delete(key);
            }
            //生成六位数验证码
            Integer code = ValidateCodeUtils.generateValidateCode(6);
            //存入redis设置为5分钟
            valueOperations.setIfAbsent(key,code,5, TimeUnit.MINUTES);
            //TODO 仅测试使用 (如果邮箱格式错误，redis仍会记录这条数据)
            System.out.println(code);
            text=Integer.toString(code);
        }
        mailMessage.setText(text);
        try{
            //发送邮件
            javaMailSender.send(mailMessage);
        }catch (Exception e){
            throw new Exception("验证码发送错误，请检查邮箱");
        }
        return R.ok("邮件发送成功");
    }


    //用户注册
    public R<LoginFormDTO> registration(RegistrationDTO registrationDTO) throws Exception {
        //判断用户名、手机号、邮箱是否存在
        String username= registrationDTO.getUsername();
        String phone= registrationDTO.getPhone();
        String email= registrationDTO.getEmail();
        //判断用户名
        LambdaQueryWrapper<User> lambdaQueryWrapperUser=new LambdaQueryWrapper<>();
        lambdaQueryWrapperUser.eq(User::getUsername,username);
        User getByUserName = getOne(lambdaQueryWrapperUser);
        if(getByUserName!=null){
            return R.error("用户名已存在");
        }
        //判断手机号
        lambdaQueryWrapperUser.clear();
        lambdaQueryWrapperUser.eq(User::getPhone,phone);
        User getByPhone = getOne(lambdaQueryWrapperUser);
        if(getByPhone!=null){
            return R.error("该手机号已注册");
        }
        //判断邮箱（不需要，在发送验证码时验证）
        //判断redis验证码
        //规定key为邮箱+操作类型
        String key=email+Operation.REGISTRATION;
        ValueOperations valueOperations = redisTemplate.opsForValue();
        Object o = valueOperations.get(key);
        //判断验证码是否失效
        if(o==null){
            return R.error("验证码已失效，请点击重新发送");
        }
        Integer code=(Integer) o;
        //判断验证码是否正确
        if(!code.equals(registrationDTO.getCode())){
            //不正确则返回
            return R.error("验证码错误");
        }
        //正确则需要删除这条redis缓存
        redisTemplate.delete(key);
        //满足条件，开始注册，按权限分类，普通用户直接注册，设备管理员、维修人员需要系统管理员审核
        Permission permission = registrationDTO.getPermission();
        //进行封装返回
        //封装user
        User user=new User();
        BeanUtils.copyProperties(registrationDTO,user);
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        user.setStatus(UserStatus.NORMAL);
        user.setPermission(permission);
        user.setIsAu(1);
        //密码进行加密
        user.setPassword(DigestUtils.md5DigestAsHex(registrationDTO.getPassword().getBytes()));
        if(permission.equals(Permission.REPAIR_USER)||permission.equals(Permission.DEVICE_ADMINISTRATOR)){
            //将isAU设为1
            user.setIsAu(0);
        }
        //存储用户数据
        save(user);
        //封装address
        Address address=new Address();
        BeanUtils.copyProperties(registrationDTO,address);
        address.setMobile(phone);
        address.setUserId(user.getId());
        //存储地址数据
        addressService.save(address);
        //发送注册成功邮件
        sendMail(MailTitle.REGISTRATION_SUCCESS,"感谢您使用本网站,您的申请已提交，将在1-7个工作日内处理",email);
        //TODO 暂时返回null，具体看前端需要什么
        LoginFormDTO loginFormDTO=new LoginFormDTO();
        loginFormDTO.setUsername(user.getUsername());
        return R.ok(loginFormDTO);
    }

    //提交维修申请 使用RabbitMQ异步通讯
    @Override
    public R malfunctionRepair(RepairDTO repairDTO) {
        //publisher
        String queueName= QueueConstant.REPAIR_QUEUE_NAME;
        String repairMessage=repairDTO.getEquipmentId()+"+"+repairDTO.getRemark();
        rabbitTemplate.convertAndSend(queueName,repairMessage);
        return R.ok("提交申请成功");
    }

    //完成维修并提交(使用MQ异步通讯)
    @Override
    public R completeRepair(CompleteRepairDTO completeRepairDTO) {
        String queueName=QueueConstant.COMPLETE_REPAIR_QUEUE_NAME;
        //员工id+维修订单id+维修情况+备注
        String message=completeRepairDTO.getUserId()+"+"
                +completeRepairDTO.getRepairId()+"+"
                +completeRepairDTO.getStatus()+"+"
                +completeRepairDTO.getRemark();
        rabbitTemplate.convertAndSend(queueName,message);
        return R.ok("完成订单提交成功");
    }

    //获取所有待审核账号
    @Override
    public R<List<User>> getAllAuUser() {
        LambdaQueryWrapper<User> lambdaQueryWrapper=new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getIsAu,0);
        List<User> users = list(lambdaQueryWrapper);
        return R.ok(users);
    }


    //同意\拒绝用户申请
    @Override
    public R AuditUser(AuditDTO auditDTO) throws Exception {
        //0表示拒绝，1表示同意
        //更新user表
        Long userId = auditDTO.getId();
        Integer status = auditDTO.getStatus();
        User user = getById(userId);
        String email = user.getEmail();
        if(status==0){
            //拒绝请求,删除这条user请求
            removeById(userId);
            //发送邮件
            sendMail(MailTitle.AUDIT_DEFAULT,"很遗憾您的注册申请未通过",email);
        }else{
            //同意请求,将user的is_au改为1
            user.setIsAu(1);
            updateById(user);
            //发送邮件
            sendMail(MailTitle.AUDIT_SUCCESS,"您的注册申请已通过，现已可登录本网站",email);
            //如果是维修人员，需要在LogStatus表中增加数据
            if(user.getPermission().equals(Permission.REPAIR_USER)){
                LogStatus logStatus=new LogStatus();
                logStatus.setUserId(userId);
                logStatus.setStatus(0);
            }
        }

        return R.ok();
    }

    @Override
    public R submitDailyLog(String log) {
        //判断是否有权限
        Long userId = UserContext.getUser();
        User user = getById(userId);
        if(!isAllow(user.getPermission(),Permission.REPAIR_USER)){
            return R.error(ResponseConstant.NOT_ALLOW);
        }
        //生成DailyMaintenance记录
        DailyMaintenance dailyMaintenance=new DailyMaintenance();
        dailyMaintenance.setUserId(userId);
        dailyMaintenance.setSubmissionTime(LocalDateTime.now());
        dailyMaintenance.setLog(log);
        //存储数据
        dailyMaintenanceService.save(dailyMaintenance);
        //更新LogStatus表中的status
        LambdaQueryWrapper<LogStatus> lambdaQueryWrapper=new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(LogStatus::getUserId,userId);
        LogStatus logStatus = logStatusService.getOne(lambdaQueryWrapper);
        logStatus.setStatus(1);
        //存储数据
        logStatusService.updateById(logStatus);
        return R.ok();
    }

    //查看自己的所有维护日志（分页查询）
    @Override
    public R<List<DailyMaintenance>> getMyDailyMaintenance() {
        Long userId = UserContext.getUser();
        LambdaQueryWrapper<DailyMaintenance> lambdaQueryWrapper=new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(DailyMaintenance::getUserId,userId);
        List<DailyMaintenance> list = dailyMaintenanceService.list(lambdaQueryWrapper);
        return R.ok(list);
    }

    //查看所有的维护记录
    @Override
    public R<List<DailyMaintenance>> getAllDailyMaintenance() {
        //确认权限
        Long userId = UserContext.getUser();
        User user = getById(userId);
        if(isAllow(user.getPermission(),Permission.DEVICE_ADMINISTRATOR)){
            //获取数据
            List<DailyMaintenance> list = dailyMaintenanceService.list();
            return R.ok(list);
        }else{
            return R.error(ResponseConstant.NOT_ALLOW);
        }
    }

    @Override
    public R<List<RegistrationDTO>> getAllUser() {
        //验证权限
        Long userId = UserContext.getUser();
        User userGetById = getById(userId);
        if(isAllow(userGetById.getPermission(),Permission.SYSTEM_ADMINISTRATOR)){
            //查找用户数据
            List<User> users = list();
            //封装数据
            List<RegistrationDTO> registrationDTOS=new ArrayList<>();
            for (User user : users) {
                RegistrationDTO registrationDTO=new RegistrationDTO();
                //查找Address数据
                LambdaQueryWrapper<Address> lambdaQueryWrapper=new LambdaQueryWrapper<>();
                lambdaQueryWrapper.eq(Address::getUserId,user.getId());
                Address address = addressService.getOne(lambdaQueryWrapper);
                //封装数据
                BeanUtils.copyProperties(user,registrationDTO);
                BeanUtils.copyProperties(address,registrationDTO);
                registrationDTO.setUserId(user.getId());
                registrationDTOS.add(registrationDTO);
            }
            //返回数据
            return R.ok(registrationDTOS);
        }else {
            return R.error(ResponseConstant.NOT_ALLOW);
        }
    }

    @Override
    public R freezeOrUnFreezeUser(FreezeOrUnFreezeUserVO freezeOrUnFreezeUserVO) {
        //判断权限
        if(judgePermission(Permission.SYSTEM_ADMINISTRATOR)){
            //进行操作
            Long userId = freezeOrUnFreezeUserVO.getUserId();
            Integer status = freezeOrUnFreezeUserVO.getStatus();
            User user=getById(userId);
            user.setStatus(UserStatus.of(status));
            updateById(user);
            //如果是冻结维修用户，则需要删除每日维护计划人员表和删除维修订单中的userId
            if(isAllow(user.getPermission(),Permission.REPAIR_USER)&&freezeOrUnFreezeUserVO.getStatus()==0){
                //删除每日维护计划人员
                MaintenanceUsersDTO maintenanceUsersDTO=new MaintenanceUsersDTO();
                List<Long> userIds=new ArrayList<>();
                userIds.add(userId);
                maintenanceUsersDTO.setUserIds(userIds);
                equipmentClient.deleteMaintenanceUsers(maintenanceUsersDTO);
                //删除维修订单中的userId
                equipmentClient.deleteRepairUser(userId);
            }
            return R.ok("冻结用户成功");
        }else {
            return R.error(ResponseConstant.NOT_ALLOW);
        }
    }

    @Override
    public R forgetPassword(ForgetPasswordVO forgetPasswordVO) {
        //判断验证码
        String email=forgetPasswordVO.getEmail();
        //规定key为邮箱+操作类型
        String key=email+Operation.FORGET_PASSWORD;
        ValueOperations valueOperations = redisTemplate.opsForValue();
        Object o = valueOperations.get(key);
        //判断验证码是否失效
        if(o==null){
            return R.error("验证码已失效，请点击重新发送");
        }
        Integer code=(Integer) o;
        //判断验证码是否正确
        if(!code.equals(forgetPasswordVO.getCode())){
            //不正确则返回
            return R.error("验证码错误");
        }
        //正确则需要删除这条redis缓存
        redisTemplate.delete(key);
        //查找用户信息
        LambdaQueryWrapper<User> lambdaQueryWrapper=new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getEmail,email);
        User user = getOne(lambdaQueryWrapper);
        //md5加密
        String password = DigestUtils.md5DigestAsHex(forgetPasswordVO.getPassword().getBytes());
        user.setPassword(password);
        //更新数据
        updateById(user);
        return R.ok("重置密码成功");
    }

    @Override
    public R<List<UserVO>> showRepaierUser() {
        //判断权限
        if(judgePermission(Permission.DEVICE_ADMINISTRATOR)){
            //获取数据
            LambdaQueryWrapper<User> lambdaQueryWrapper=new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(User::getPermission,Permission.REPAIR_USER);
            List<User> users = list(lambdaQueryWrapper);
            //封装数据
            List<UserVO> userVOS=new ArrayList<>();
            for (User user : users) {
                UserVO userVO=new UserVO();
                BeanUtils.copyProperties(user,userVO);
                userVOS.add(userVO);
            }
            //返回数据
            return R.ok(userVOS);
        }else {
            return R.error(ResponseConstant.NOT_ALLOW);
        }
    }

    @Override
    public R alertUser(Long alertsId, Long userId) {
        //权限判断
        if (judgePermission(Permission.DEVICE_ADMINISTRATOR)){
            return equipmentClient.alertUser(alertsId,userId);
        }else {
            return R.error(ResponseConstant.NOT_ALLOW);
        }
    }

    @Override
    public R changeRepairStatus(Long repairId) {
        //权限判断
        if(judgePermission(Permission.REPAIR_USER)){
            return equipmentClient.changeRepairStatus(repairId);
        }else {
            return R.error(ResponseConstant.NOT_ALLOW);
        }
    }

    @Override
    public R addMaintenanceSchedule(MaintenanceScheduleDTO maintenanceScheduleDTO) {
        //权限判断
        if(judgePermission(Permission.DEVICE_ADMINISTRATOR)){
            Long userId = UserContext.getUser();
            maintenanceScheduleDTO.setUserId(userId);
            return equipmentClient.addMaintenanceSchedule(maintenanceScheduleDTO);
        }else{
            return R.error(ResponseConstant.NOT_ALLOW);
        }
    }

    @Override
    public R arrangementMaintenanceSchedule(MaintenanceUsersDTO maintenanceUsersDTO) {
        //权限判断
        if (judgePermission(Permission.DEVICE_ADMINISTRATOR)){
            return equipmentClient.arrangementMaintenanceSchedule(maintenanceUsersDTO);
        }else {
            return R.error(ResponseConstant.NOT_ALLOW);
        }
    }

    @Override
    public R<List<RepairUserVO>> getRepairUsers(List<Long> ids) {
        //查找数据
        LambdaQueryWrapper<User> lambdaQueryWrapper=new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getPermission,Permission.REPAIR_USER);
        lambdaQueryWrapper.eq(User::getStatus,1);
        //排除在ids里的用户
        lambdaQueryWrapper.notIn(ids!=null,User::getId,ids);
        List<User> users = list(lambdaQueryWrapper);
        List<RepairUserVO> repairUserVOS=new ArrayList<>();
        //封装数据
        for (User user : users) {
            RepairUserVO repairUserVO=new RepairUserVO();
            BeanUtils.copyProperties(user,repairUserVO);
            repairUserVOS.add(repairUserVO);
        }
        //返回数据
        return R.ok(repairUserVOS);
    }

    @Override
    public R<List<MaintenanceSchedulesVO>> getAllMaintenanceSchedule() {
        //判断权限
        if(judgePermission(Permission.DEVICE_ADMINISTRATOR)){
            return equipmentClient.getAllMaintenanceSchedule();
        }else{
            return R.error(ResponseConstant.NOT_ALLOW);
        }
    }

    @Override
    public R updateMaintenanceSchedule(MaintenanceSchedulesVO maintenanceSchedulesVO) {
        //权限判断
        if(judgePermission(Permission.DEVICE_ADMINISTRATOR)){
            return equipmentClient.updateMaintenanceSchedule(maintenanceSchedulesVO);
        }else {
            return R.error(ResponseConstant.NOT_ALLOW);
        }
    }

    @Override
    public R<List<MaintenanceSchedulesVO>> getMyMaintenanceSchedules() {
        if(judgePermission(Permission.REPAIR_USER)){
            //获取用户id，传给equipment模块
            Long userId = UserContext.getUser();
            return equipmentClient.getMyMaintenanceSchedules(userId);
        }else {
            return R.error(ResponseConstant.NOT_ALLOW);
        }

    }

    @Override
    public R<List<Repair>> getAllRepair() {
        //权限判断
        if(judgePermission(Permission.DEVICE_ADMINISTRATOR)){
            return equipmentClient.getAllRepair();
        }else {
            return R.error(ResponseConstant.NOT_ALLOW);
        }
    }


    public boolean isAllow(Permission userPermission,Permission allowPermission){
        return userPermission.equals(allowPermission);
    }
    //判断是否有权限
     public boolean judgePermission(Permission permission){
        //获取用户权限
         Long userId = UserContext.getUser();
         User user = getById(userId);
         return user.getPermission().equals(permission);
     }




    //MultipartFile 定义的实体类名称需要和前端传来的数据名称一致
    public R<String> upload(MultipartFile file){
        try {
            //获取原始文件名
            String originalFilename = file.getOriginalFilename();
            //获取后缀
            String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
            //构造新的文件名
            String objectName= UUID.randomUUID().toString()+extension;
            //文件请求的路径
            String filePath = aliOssUtil.upload(file.getBytes(), objectName);
            //在存储到数据库user-face

            return R.ok(filePath);
        } catch (IOException e) {
            log.error("文件上传失败：{}",e);
        }
        return R.error("文件上传失败");
    }
}

